<?php

require_once('Classes/Xml/ObjectArrayIterator.php');

		class SimpleObject {
			var $sName;
			function SimpleObject ( $sName ) {
				$this->sName = $sName;	
			}
			function GetName( $sSuffix ) {
				return $this->sName . $sSuffix;
			}
		}	
		
		class OtherSimpleObject {
			var $sValue;
			function OtherSimpleObject( $sValue ) {
				$this->sValue = $sValue;	
			}	
			function GetValue() {
				return $this->sValue;
			}
		}


class Test_ObjectArrayIterator extends UnitTestCase {
    
    function test_HasSomeElementsReturnsFalseForANewIterator() {
    	$oIterator = new ObjectArrayIterator();
        $this->assertFalse(  $oIterator->HasSomeElements() );
    }

    function test_HasSomeElementsReturnsTrueForAnIteratorThatHasHasAnElementAdded() {
    	$oIterator = new ObjectArrayIterator();
    	$oIterator->AddElement( 'thing' );
        $this->assertTrue(  $oIterator->HasSomeElements() );
    }

	function test_HasSomeElementsReturnsTrueForAnIteratorThatHasHasSeveralElementsAdded() {
    	$oIterator = new ObjectArrayIterator();
    	$oIterator->AddElement( 'thing' );
    	$oIterator->AddElement( 'OtherThing' );
    	$oIterator->AddElement( 15 );
    	$oIterator->AddElement( new ObjectArrayIterator() );
        $this->assertTrue(  $oIterator->HasSomeElements() );
	}

	function test_GetNextElementReturnsFalseForAnEmptyIterator() {
    	$oIterator = new ObjectArrayIterator();
        $this->assertFalse(  $oIterator->GetNextElement() );
	}

	function test_GetNextElementCalledAgainstAnIteratorWithASingleElementReturnsThatElementOnlyOnce() {
    	$oIterator = new ObjectArrayIterator();
    	$oThing = 'thing';
    	$oIterator->AddElement( $oThing );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing );
        $this->assertFalse( $oIterator->GetNextElement() );
	}

	function test_GetNextElementCalledAgainstAnIteratorWithMultipleElementsWillReturnEachElementInTurnOnlyOne() {
		$oThing1 = 'thing';
		$oThing2 = 15;
		$oThing3 = new ObjectArrayIterator();

    	$oIterator = new ObjectArrayIterator();
    	$oIterator->AddElement( $oThing1 );
    	$oIterator->AddElement( $oThing2 );
    	$oIterator->AddElement( $oThing3 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing1 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing2 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing3 );
        $this->assertFalse( $oIterator->GetNextElement() );
	}

	function test_HasAnotherElementReturnsTrueIfGetNextElementWouldReturnAnElement() {
    	$oIterator = new ObjectArrayIterator();
    	$sThing = 'thing';
    	$oIterator->AddElement( $sThing );
        $this->assertTrue(  $oIterator->HasAnotherElement() );
        $this->assertIdentical( $oIterator->GetNextElement(), $sThing );
	}
	
	function test_HasAnotherElementReturnsFalseIfGetNextElementWouldNotReturnAnElement() {
    	$oIterator = new ObjectArrayIterator();
    	$sThing = 'thing';
    	$oIterator->AddElement( $sThing );
        $this->assertIdentical( $oIterator->GetNextElement(), $sThing );
        $this->assertFalse(  $oIterator->HasAnotherElement() );
		
	}

	function test_HasAnotherElementReturnsFalseIfTheIteratorDoesNotContainAnyElements() {
    	$oIterator = new ObjectArrayIterator();
        $this->assertFalse(  $oIterator->HasAnotherElement() );
	}

	function test_AnObjectArrayIteratorWillAllowAtLeast2ToThePower16ElementsToBeStored() {

		$aThings = array();
		$oIterator = new ObjectArrayIterator();

		for( $i=0; $i <= 65536; $i++ ) {
			$aThings[] = $i;
			$oIterator->AddElement( $i );
		}

		$aReturn = array();
		while ( $oIterator->HasAnotherElement() ) {
			$aReturn[] = $oIterator->GetNextElement();	
		}
		
		$this->assertIdentical( $aThings, $aReturn );
		
	}

	function test_RewindElementIteratorWillReturnTheInternalPointerToTheStartSoThatTheNextCallToGetNextElementReturnsTheFirstElement() {

		$oThing1 = 'thing';
		$oThing2 = 15;
		$oThing3 = new ObjectArrayIterator();

    	$oIterator = new ObjectArrayIterator();
    	$oIterator->AddElement( $oThing1 );
    	$oIterator->AddElement( $oThing2 );
    	$oIterator->AddElement( $oThing3 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing1 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing2 );

		$oIterator->RewindElementIterator();
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing1 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing2 );
        $this->assertIdentical( $oIterator->GetNextElement(), $oThing3 );
        $this->assertFalse( $oIterator->GetNextElement() );

	}
	
	function test_MergeElementsWillCombineTheContentsOfThePassedIteratorWithTheSubjectIteratorAddingTheNewElementsAtTheEndOfTheList() {
		$oThing1 = 'thing';
		$oThing2 = 15;
		$oThing3 = new ObjectArrayIterator();
		$oThing4 = '99 red balloons';

    	$oSubjectIterator = new ObjectArrayIterator();
    	$oSubjectIterator->AddElement( $oThing1 );

    	$oObjectIterator = new ObjectArrayIterator();
    	$oObjectIterator->AddElement( $oThing2 );
    	$oObjectIterator->AddElement( $oThing3 );
    	$oObjectIterator->AddElement( $oThing4 );

    	$oSubjectIterator->MergeElements( $oObjectIterator );

        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing1 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing2 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing3 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing4 );

	}

	function test_MergeElementsWillCombineTheContentsOfThePassedIteratorWithTheSubjectIteratorEvenIfSomeOfTheElementsAreIdentical() {

		$oThing1 = 'thing';
		$oThing2 = 15;
		$oThing3 = new ObjectArrayIterator();
		$oThing4 = '99 red balloons';

    	$oSubjectIterator = new ObjectArrayIterator();
    	$oSubjectIterator->AddElement( $oThing1 );
    	$oSubjectIterator->AddElement( $oThing3 );
    	$oSubjectIterator->AddElement( $oThing4 );

    	$oObjectIterator = new ObjectArrayIterator();
    	$oObjectIterator->AddElement( $oThing2 );
    	$oObjectIterator->AddElement( $oThing3 );
    	$oObjectIterator->AddElement( $oThing4 );

    	$oSubjectIterator->MergeElements( $oObjectIterator );

        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing1 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing3 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing4 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing2 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing3 );
        $this->assertIdentical( $oSubjectIterator->GetNextElement(), $oThing4 );
	}

	function test_IfPassedAgainstAnEmptyIteratorThenMergeElementsWillResultInTheSubjectAndObjectBeingIdentical() {

		$oThing1 = 'thing';
		$oThing2 = 15;
		$oThing3 = new ObjectArrayIterator();

    	$oObjectIterator = new ObjectArrayIterator();
    	$oObjectIterator->AddElement( $oThing1 );
    	$oObjectIterator->AddElement( $oThing2 );
    	$oObjectIterator->AddElement( $oThing3 );

		$oSubjectIterator = new ObjectArrayIterator();
		$oSubjectIterator->MergeElements( $oObjectIterator );

        $this->assertIdentical( $oObjectIterator, $oSubjectIterator );
	}

	function test_ReturnArrayFromCallbackWillLoopOverAllTheElementsAndCallTheSpecifiedFunctionAgainstEachElementPassingTheSpecifiedParameterValueAndReturnTheResultsAsANumericallyIndexArray() {
			
		$aThings = array();
		$oIterator = new ObjectArrayIterator();

		for( $i=0; $i <= 10; $i++ ) {
			$aThings[] = (string)$i . 'XXX';
			$oIterator->AddElement( new SimpleObject( (string)$i ) );
		}
		$this->assertIdentical( $aThings, $oIterator->ReturnArrayFromCallback( 'GetName', 'XXX' ) );
	}

	function test_ThePositionOfTheInternalElementPointerDoesNotAffectTheReturnFromReturnArrayFromCallback() {
			
		$aThings = array();
		$oIterator = new ObjectArrayIterator();

		for( $i=0; $i <= 10; $i++ ) {
			$aThings[] = (string)$i . 'XXX';
			$oIterator->AddElement( new SimpleObject( (string)$i ) );
		}
		$oIterator->GetNextElement();
		$oIterator->GetNextElement();
		$oIterator->GetNextElement();
		$this->assertIdentical( $aThings, $oIterator->ReturnArrayFromCallback( 'GetName', 'XXX' ) );
	}
	
	function test_CallingReturnArrayFromCallbackAgainstAnEmptyIteratorReturnsAnEmptyArray() {
		
		$oIterator = new ObjectArrayIterator();
		$this->assertIdentical( array(), $oIterator->ReturnArrayFromCallback( 'GetName', 'XXX' ) );
	}

	function test_CallingReturnArrayFromCallbackPassingAFunctionThatIsNotImplementedForEveryElementResultsInThoseElementsWithoutTheFunctionBeingRepresentedByNull() {

		$aThings = array();
		$oIterator = new ObjectArrayIterator();

		for( $i=0; $i <= 10; $i++ ) {
			if ( $i==5 ) {
				$aThings[] = null;
				$oIterator->AddElement( new OtherSimpleObject( (string)$i ) );
			} elseif ( $i==7 ) {
				$aThings[] = null;
				$oIterator->AddElement( 15 );
			} else {
				$aThings[] = (string)$i . 'XXX';
				$oIterator->AddElement( new SimpleObject( (string)$i ) );
			}
		}
		$oIterator->GetNextElement();
		$oIterator->GetNextElement();
		$oIterator->GetNextElement();
		$this->assertIdentical( $aThings, $oIterator->ReturnArrayFromCallback( 'GetName', 'XXX' ) );

	}
}

?>
